#include "definitions.h"
#include <rtthread.h>

#include "osal_rtthread.h"

// *****************************************************************************
// *****************************************************************************
// Section: Interface Routines Group Defintions
// *****************************************************************************
// *****************************************************************************

/* Critical Section group */
// *****************************************************************************
/* Function: OSAL_CRITSECT_DATA_TYPE OSAL_CRIT_Enter(OSAL_CRIT_TYPE severity)
 */
OSAL_CRITSECT_DATA_TYPE OSAL_CRIT_Enter (OSAL_CRIT_TYPE severity)
{
    switch (severity) {
        //case OSAL_CRIT_TYPE_LOW:
        /* LOW priority critical sections just disable the scheduler */
        //vTaskSuspendAll();
        //break;

        case OSAL_CRIT_TYPE_HIGH:
            /* HIGH priority critical sections disable interrupts */
            rt_enter_critical();
            break;
    }
    return 0;
}

// *****************************************************************************
/* Function: void OSAL_CRIT_Leave(OSAL_CRIT_TYPE severity, OSAL_CRITSECT_DATA_TYPE status)
 */
void OSAL_CRIT_Leave (OSAL_CRIT_TYPE severity, OSAL_CRITSECT_DATA_TYPE status)
{
    switch (severity) {
        //case OSAL_CRIT_TYPE_LOW:
        /* LOW priority resumes scheduler */
        //xTaskResumeAll();
        //break;

        case OSAL_CRIT_TYPE_HIGH:
            /* HIGH priority renables interrupts */
            rt_exit_critical();
            break;
    }
}

// *****************************************************************************
/* Function: OSAL_RESULT OSAL_SEM_Create(OSAL_SEM_HANDLE_TYPE semID, OSAL_SEM_TYPE type,
                                uint8_t maxCount, uint8_t initialCount)
 */
OSAL_RESULT OSAL_SEM_Create (OSAL_SEM_HANDLE_TYPE *semID, OSAL_SEM_TYPE type,
                             uint8_t maxCount, uint8_t initialCount)
{
    char name[RT_NAME_MAX];
    static rt_uint16_t psem_number = 0;

    rt_snprintf (name, sizeof (name), "psem%02d", psem_number++);

    switch (type) {
        case OSAL_SEM_TYPE_BINARY:
            if ( initialCount <= 1) {
                /* Binary semaphores created using xSemaphoreCreateBinary() are created in
                 * a state such that the semaphore must first be 'given' before it can be
                 * 'taken'. So call to OSAL_SEM_Create() with initialCount = 1 then
                 * Binary semaphore must be created in a state such that the first call to
                 * 'take' the semaphore would pass.
                 */
                *semID = rt_sem_create (name, 0, RT_IPC_FLAG_FIFO);

                if (*semID != NULL && initialCount == 1) {
                    if (rt_sem_release (*semID) == RT_EOK) {
                        return OSAL_RESULT_TRUE;
                    } else {
                        return OSAL_RESULT_FALSE;
                    }
                }
            } else { // for a Binary Semaphore initialCount must be either "0" or "1"
                return OSAL_RESULT_FALSE;
            }
            break;

        case OSAL_SEM_TYPE_COUNTING:
            *semID = rt_sem_create (name, initialCount, RT_IPC_FLAG_FIFO);
            break;

        default:
            *semID = NULL;
            return OSAL_RESULT_NOT_IMPLEMENTED;
    }

    if (*semID == NULL) {
        return OSAL_RESULT_FALSE;
    }

    return OSAL_RESULT_TRUE;
}

// *****************************************************************************
/* Function: OSAL_RESULT OSAL_SEM_Delete(OSAL_SEM_HANDLE_TYPE semID)
 */
OSAL_RESULT OSAL_SEM_Delete (OSAL_SEM_HANDLE_TYPE *semID)
{
    if (*semID == RT_NULL)
        return OSAL_RESULT_FALSE;

    rt_sem_delete (*semID);
    return OSAL_RESULT_TRUE;
}

// *****************************************************************************
/* Function: OSAL_RESULT OSAL_SEM_Pend(OSAL_SEM_HANDLE_TYPE semID, uint16_t waitMS)
 */
OSAL_RESULT OSAL_SEM_Pend (OSAL_SEM_HANDLE_TYPE *semID, uint16_t waitMS)
{
    rt_err_t result;

    result = rt_sem_take (*semID, waitMS);
    if (result == RT_EOK)
        return OSAL_RESULT_TRUE;

    return OSAL_RESULT_FALSE;
}

// *****************************************************************************
/* Function: OSAL_RESULT OSAL_SEM_Post(OSAL_SEM_HANDLE_TYPE semID)
 */
OSAL_RESULT OSAL_SEM_Post (OSAL_SEM_HANDLE_TYPE *semID)
{
    rt_err_t result;

    if (*semID == RT_NULL)
        return OSAL_RESULT_FALSE;

    result = rt_sem_release (*semID);
    if (result == RT_EOK)
        return OSAL_RESULT_TRUE;

    return OSAL_RESULT_FALSE;
}

// *****************************************************************************
/* Function: OSAL_RESULT OSAL_SEM_PostISR(OSAL_SEM_HANDLE_TYPE semID)
 */
OSAL_RESULT OSAL_SEM_PostISR (OSAL_SEM_HANDLE_TYPE *semID)
{
    (*semID)++;
    return OSAL_RESULT_TRUE;
}

// *****************************************************************************
/* Function: uint8_t OSAL_SEM_GetCount(OSAL_SEM_HANDLE_TYPE semID)
 */
uint8_t OSAL_SEM_GetCount (OSAL_SEM_HANDLE_TYPE *semID)
{
    return ((*semID)->value) & 0xFF;
}

// *****************************************************************************
/* Function: OSAL_RESULT OSAL_MUTEX_Create(OSAL_MUTEX_HANDLE_TYPE mutexID)
 */
OSAL_RESULT OSAL_MUTEX_Create (OSAL_MUTEX_HANDLE_TYPE *mutexID)
{
    char name[RT_NAME_MAX];
    static rt_uint16_t pthread_mutex_number = 0;

    if (*mutexID != RT_NULL)
        return OSAL_RESULT_FALSE;

    /* build mutex name */
    rt_snprintf (name, sizeof (name), "pmtx%02d", pthread_mutex_number ++);

    /* init mutex lock */
    *mutexID = rt_mutex_create (name, RT_IPC_FLAG_FIFO);
    if (*mutexID == RT_NULL)
        return OSAL_RESULT_FALSE;

    return OSAL_RESULT_TRUE;
}

// *****************************************************************************
/* Function: OSAL_RESULT OSAL_MUTEX_Delete(OSAL_MUTEX_HANDLE_TYPE mutexID)
 */
OSAL_RESULT OSAL_MUTEX_Delete (OSAL_MUTEX_HANDLE_TYPE *mutexID)
{
    rt_err_t result;

    if (*mutexID == RT_NULL)
        return OSAL_RESULT_FALSE;

    result = rt_mutex_delete (*mutexID);
    if (result != RT_EOK)
        return OSAL_RESULT_FALSE;

    return OSAL_RESULT_TRUE;
}

// *****************************************************************************
/* Function: OSAL_RESULT OSAL_MUTEX_Lock(OSAL_MUTEX_HANDLE_TYPE mutexID, uint16_t waitMS)
 */
OSAL_RESULT OSAL_MUTEX_Lock (OSAL_MUTEX_HANDLE_TYPE *mutexID, uint16_t waitMS)
{
    rt_err_t result;

    result = rt_mutex_take (*mutexID, waitMS);
    if (result == RT_EOK)
        return OSAL_RESULT_TRUE;

    return OSAL_RESULT_FALSE;
}

// *****************************************************************************
/* Function: OSAL_RESULT OSAL_MUTEX_Unlock(OSAL_MUTEX_HANDLE_TYPE mutexID)
 */
OSAL_RESULT OSAL_MUTEX_Unlock (OSAL_MUTEX_HANDLE_TYPE *mutexID)
{
    rt_err_t result;

    if (* mutexID == RT_NULL)
        return OSAL_RESULT_FALSE;

    result = rt_mutex_release (* mutexID);
    if (result == RT_EOK)
        return OSAL_RESULT_TRUE;

    return OSAL_RESULT_FALSE;
}

// *****************************************************************************
/* Function: OSAL_RESULT OSAL_Initialize()

  Summary:
    Perform OSAL initialization.

  Description:
     This function should be called near the start of main in an application
     that will use an underlying RTOS. This permits the RTOS to perform
     any one time initialization before the application attempts to create
     drivers or other items that may use the RTOS. Typical actions performed by
     OSAL_Initialize would be to allocate and prepare any memory pools for
     later use.

  Precondition:
    None.

  Parameters:
    None.

  Returns:
    OSAL_RESULT_TRUE  - Initialization completed successfully.

  Example:
    <code>
     int main()
     {
         OSAL_Initialize();

         App_Init();
         OSAL_Start();
     }
    </code>

  Remarks:
 */
OSAL_RESULT OSAL_Initialize()
{
    // nothing required
    return OSAL_RESULT_TRUE;
}
